#include <bits/stdc++.h>

using namespace std;

// 买卖股票的最佳时机含冷冻期
// 给定一个整数数组prices，其中第  prices[i] 表示第 i 天的股票价格
// 设计一个算法计算出最大利润
// 在满足以下约束条件下，你可以尽可能地完成更多的交易（多次买卖一支股票）:
// 卖出股票后，你无法在第二天买入股票 (即冷冻期为 1 天)
// 注意：你不能同时参与多笔交易（你必须在再次购买前出售掉之前的股票）
// 测试链接 : https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-with-cooldown/

class Solution 
{
public:
    int maxProfit1(vector<int>& prices) 
    {
        int n = prices.size();
        if(n < 2) return 0;
        // prepare[i] : 0...i范围上，可以做无限次交易，获得收益的同时一定要扣掉
        // 一次购买，所有情况中的最好情况，同时需要考虑冷冻期
        // done[i] : 0...i范围上，可以做无限次交易，能获得的最大收益，同时需要考虑冷冻期
        int prepare[n], done[n];
        done[0] = 0;
        prepare[1] = max(-prices[0], -prices[1]);
        done[1] = max(0, prices[1] - prices[0]);
        for(int i = 2; i < n; ++i)
        {
            done[i] = max(done[i - 1], prepare[i - 1] + prices[i]);
            prepare[i] = max(prepare[i - 1], done[i - 2] - prices[i]);
        }
        return done[n - 1];
    }

	// 只是把方法1做了变量滚动更新(空间压缩)
	// 并没有新的东西
    int maxProfit2(vector<int>& prices) 
    {
        int n = prices.size();
        if(n < 2) return 0;
        // prepare : prepare[i-1]
        int prepare = max(-prices[0], -prices[1]);
        // done2 : done[i-2]
        int done2 = 0;
        // done1 : done[i-1]
        int done1 = max(0, prices[1] - prices[0]);
        for(int i = 2, curDone; i < n; ++i)
        {
            // curDone : done[i]
            curDone = max(done1, prepare + prices[i]);
            // prepare : prepare[i-1] -> prepare[i]
            prepare = max(prepare, done2 - prices[i]);
            done2 = done1;
            done1 = curDone;
        }
        return done1;
    }
};


class Solution 
{
public:
    int maxProfit(vector<int>& prices) 
    {
        int n = prices.size();
        int dp[n][3];
        // dp[i][0] : 当天持有股票且下一跳不会处在冷冻期时的最大利润
        // dp[i][1] : 当天不持有股票且下一天不会处在冷冻期时的最大利润
        // dp[i][2] : 当天将股票卖出且下一天将会处在冷冻期时的最大利润
        memset(dp, 0, sizeof dp);
        dp[0][0] = -prices[0];
        for(int i = 1; i < n; ++i)
        {
            // dp[i - 1][0] ：不买入股票，延续前一天的状态
            // dp[i - 1][1] - prices[i] ：前一天不持有股票且今天不会处在冷冻期，第i天买入股票
            dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]);
            // dp[i - 1][1] ：不买入股票，延续前一天的状态
            // dp[i - 1][2] ：第i天处在冷冻期，下一天就不会处在冷冻期了
            dp[i][1] = max(dp[i - 1][1], dp[i - 1][2]);
            // dp[i - 1][0] + prices[i] ：第i天卖出股票，下一天处在冷冻期
            dp[i][2] = dp[i - 1][0] + prices[i];
        }
        return max(dp[n - 1][1], dp[n - 1][2]);
    }
};